package com.hsogoo.avatar.spring;

import com.hsogoo.avatar.annotations.AvatarInvoke;
import com.hsogoo.avatar.control.RateLimiterControl;
import com.hsogoo.avatar.model.InvokeMethod;
import com.hsogoo.avatar.proxy.DefaultAvatarProxyFactory;
import com.hsogoo.avatar.registry.AvatarRegistry;
import com.hsogoo.avatar.registry.InvokeMethodRegistry;
import com.hsogoo.avatar.registry.LimitControlRegistry;
import com.hsogoo.avatar.registry.RegistryLoader;
import com.hsogoo.avatar.registry.RegistryProvider;
import com.hsogoo.avatar.registry.ServerListChangeListener;
import com.hsogoo.avatar.registry.ServiceMeta;
import com.hsogoo.avatar.utils.ConfigUtil;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @Author huangsaigang
 * Created @2018/9/30.
 */
@Component
@Slf4j
public class AvatarInvokerBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Field[] fields = bean.getClass().getDeclaredFields();
        for(Field field : fields){
            if(field.isAnnotationPresent(AvatarInvoke.class)){
                AvatarInvoke avatarInvoke = field.getAnnotation(AvatarInvoke.class);
                field.setAccessible(true);
                //注册到InvokeMethod缓存中
                registerInvokeMethod(field, avatarInvoke);
                //注册客户端限流器
                if(avatarInvoke.limit() > 0){
                    LimitControlRegistry.register(beanName, new RateLimiterControl(avatarInvoke.limit()));
                }

                try{
                    //替换成代理类
                    Object proxy = DefaultAvatarProxyFactory.getInstance().createProxy(field.getType());
                    field.set(bean, proxy);
                }catch (Exception e){

                }
                AvatarRegistry registry = RegistryProvider.getRegistry(avatarInvoke.registry());
                ServiceMeta serviceMeta = new ServiceMeta(avatarInvoke.group(), field.getType().getName(), avatarInvoke.version());
                registry.subscribe(serviceMeta);
            }
        }
        return bean;
    }

    private void registerInvokeMethod(Field field, AvatarInvoke avatarInvoke) {
        Method[] methods = field.getType().getDeclaredMethods();
        for (Method method : methods) {
            InvokeMethod invokeMethod = new InvokeMethod();
            invokeMethod.setClassName(field.getType().getName());
            invokeMethod.setArgTypes(method.getParameterTypes());
            invokeMethod.setGroup(avatarInvoke.group());
            invokeMethod.setVersion(avatarInvoke.version());
            invokeMethod.setRegistry(avatarInvoke.registry());
            invokeMethod.setTimeout(avatarInvoke.timeout());
            invokeMethod.setLimit(avatarInvoke.limit());
            invokeMethod.setFallback(avatarInvoke.fallback());
            InvokeMethodRegistry.register(method, invokeMethod);
        }
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
